home *** CD-ROM | disk | FTP | other *** search
/ Developer CD Series 1992 June: ROMin Holiday / ADC Developer CD (1992-06) (''ROMin Holiday'')_iso / Developer Connection - 06-1992.iso / Periodicals / develop / develop 10 code / LWFontUtility / NamerUtilDev / NamerUTIL.c < prev    next >
Encoding:
C/C++ Source or Header  |  1992-04-08  |  14.2 KB  |  364 lines  |  [TEXT/MPS ]

  1. /*****************************************************************************************
  2.  
  3. NamerUTIL.c - The NamerUTIL, a UTIL that allows the LaserWriter Font Utility to rename
  4.               PostScript printers.
  5.  
  6. Written by Bryan K. Ressler (Beaker), 10/8/91
  7.  
  8. *****************************************************************************************/
  9.  
  10. /* --- Includes ----------------------------------------------------------------------- */
  11. #include <Types.h>                    /* Macintosh includes */
  12. #include <Memory.h>
  13. #include <Resources.h>
  14. #include <QuickDraw.h>
  15. #include <Dialogs.h>
  16. #include <Printing.h>
  17. #include <ToolUtils.h>
  18. #include <Errors.h>
  19.  
  20. #include "UTIL.h"                    /* Standard UTIL constants and structs */
  21. #include "NamerResIDs.h"            /* "Relative" resource IDs */
  22.  
  23. /* --- Defines ------------------------------------------------------------------------ */
  24. #define kMinVersion        1            /* The minimum format version we'll run */ 
  25.  
  26. #define kPSErrStr        1            /* Strings in the 'STR#' kNamerStrs */
  27. #define kExitVerStr        2
  28. #define kRenameStartStr    3
  29. #define kRenameEndStr    4
  30.  
  31. #define kNDDummy        0            /* Item numbers in the Namer dialog box */
  32. #define kNDRename        1
  33. #define kNDCancel        2
  34. #define kNDNewName        6
  35. #define kNDBoldOutline    7
  36.  
  37. #define kReturnKey        0x0d        /* Key and character code constants */
  38. #define kEnterKey        0x03
  39. #define kBackspaceKey    0x08
  40. #define kAtChar            '@'
  41. #define kColonChar        ':'
  42. #define kLowASCII        0x7f
  43.  
  44. #define kMaxNameLength    30            /* Maximum printer name length */
  45. #define kNameBufLen        40            /* Size of buffers for holding printer names */
  46. #define kCompStrLen        80            /* Size of buffers for parse strings */
  47.  
  48. /* --- Prototypes --------------------------------------------------------------------- */
  49. pascal Boolean            Utility_Open(LWFUParmBlk *pb);
  50. pascal Boolean            Utility_Delta(LWFUParmBlk *pb);
  51. pascal unsigned long    Utility_Prime(LWFUParmBlk *pb);
  52. pascal void                Utility_Close(LWFUParmBlk *pb);
  53. pascal short            ExitBufferRtn(short length, LWFUParmBlk *pb);
  54. pascal Boolean            NamerFilter(DialogPtr TheDialog, EventRecord *TheEvent,
  55.                             short *ItemHit);
  56. short                    RenamePrinter(LWFUParmBlk *pb);
  57.  
  58. /* ------------------------------------------------------------------------------------ */
  59. pascal Boolean Utility_Open(LWFUParmBlk *pb)
  60. {
  61.     /*
  62.         Normally Utility_Open does two things -- it tells the LaserWriter Font Utility
  63.         whether it should install this UTIL or not and, if needed, it allocates any
  64.         memory the UTIL might need.
  65.         
  66.         For our UTIL, we don't need any memory, so all we do is check to make sure that
  67.         the parmeter block is recent enough for us, and if so, return TRUE, which means
  68.         "install me!"
  69.     */
  70.     return(pb->version >= kMinVersion);
  71. }
  72.  
  73. /* ------------------------------------------------------------------------------------ */
  74. pascal Boolean Utility_Delta(LWFUParmBlk *pb)
  75. {
  76. #pragma unused(pb)
  77.  
  78.     /*
  79.         Utility_Delta is called every time the printer has been changed in the Chooser.
  80.         If your UTIL is device- or characteristic-specific, it can use the Utility_Delta
  81.         routine to decide whether it should be dimmed or not.  To help your UTIL decide,
  82.         the parameter block has lots of useful printer configuration information in its
  83.         printerInfo structure.  If that's not enough, you can call DoWrite from your
  84.         Utility_Delta routine to send some PostScript code down that determines the
  85.         printer is up to snuff, then return TRUE/FALSE depending upon what comes back
  86.         from the printer.  Since we can rename any PostScript device (assuming it's
  87.         exitserver password is 0), we just return TRUE here, so this UTIL will always
  88.         be available (never dimmed).
  89.     */
  90.     return(true);
  91. }
  92.  
  93. /* ------------------------------------------------------------------------------------ */
  94. pascal unsigned long Utility_Prime(LWFUParmBlk *pb)
  95. {
  96.     /*
  97.         Utility_Prime is the routine that gets called when the user chooses your UTIL
  98.         from the Utilities menu.  It should carry out the main function of your UTIL.
  99.         For us, we call RenamePrinter to pose the dialog and rename the printer.  If
  100.         RenamePrinter returns TRUE, meaning it successfully renamed the printer, we
  101.         use the following return codes:
  102.         
  103.             Return code            Description
  104.             -----------------    --------------------------------------------------------
  105.             urCheckPrinter        Tells the LWFU that the printer may have changed
  106.             urCheckFeatures        Tells the LWFU to re-query the printer for features
  107.             urEraseLists        Tells the LWFU to forget any font lists it has around
  108.         
  109.         Basically, we're telling it to forget everything and start over, since the
  110.         printer has been renamed.  urCheckPrinter and urCheckFeatures have the side-
  111.         effect of causing the Utility_Delta routines to be called for all the UTILs.
  112.         
  113.         If the user cancelled the Rename dialog or the printer couldn't be renamed
  114.         because of some PostScript error, RenamePrinter returns FALSE, in which case
  115.         we just return urNoAction, like nothing ever happened (RenamePrinter, however,
  116.         already put up an alert describing the problem to the user).
  117.     */
  118.     if (RenamePrinter(pb))
  119.         return(urCheckPrinter | urCheckFeatures | urEraseLists);
  120.     else return(urNoAction);
  121. }
  122.  
  123. /* ------------------------------------------------------------------------------------ */
  124. pascal void Utility_Close(LWFUParmBlk *pb)
  125. {
  126. #pragma unused(pb)
  127.     /*
  128.         Normally, Utility_Close releases storage the UTIL might have allocated and
  129.         stuffed into pr->uStorage.  Since we don't have any "global" storage, we
  130.         don't do anything in this routine.
  131.     */
  132. }
  133.  
  134. /* ------------------------------------------------------------------------------------ */
  135. pascal short ExitBufferRtn(short length, LWFUParmBlk *pb)
  136. {
  137.     Handle    dataHandle;                    /* Our "handlized" copy of the printer response */
  138.     short    status;                        /* The return code */
  139.     char    psErrorText[kCompStrLen];    /* Buffer for our "fail" test */
  140.     char    exitText[kCompStrLen];        /* Buffer for our "success" test */
  141.  
  142.     /*
  143.         ExitBufferRtn's job is to understand the text feedback that comes back from
  144.         the printer.  Really all that means is comparing it with known strings.
  145.         So here we retrieve the text we'll use to detect an error (i.e. kPSErrStr),
  146.         and the text we'll use to verify that we successfully exited the server
  147.         loop (i.e. kExitVerStr).
  148.     */
  149.     GetIndString(psErrorText, pb->resSpace + kNamerStrs, kPSErrStr);
  150.     GetIndString(exitText, pb->resSpace + kNamerStrs, kExitVerStr);
  151.  
  152.     /*
  153.         Now, in order to make use of everyone's favorite routine, Munger, we
  154.         "handlize" the data that came back from the printer.
  155.     */
  156.     PtrToHand(pb->callBacks->PAPReadBuffer, &dataHandle, length);
  157.     
  158.     /*
  159.         Now, we search dataHandle looking for either psErrorText or exitText,
  160.         and set the appropriate status return code.
  161.     */
  162.     if (Munger(dataHandle, 0, psErrorText + 1, *psErrorText, nil, 0) >= 0)
  163.         status = printerError;
  164.     else if (Munger(dataHandle, 0, exitText + 1, *exitText, nil, 0) >= 0)
  165.         status = noErr;
  166.     else status = printerError;
  167.     
  168.     /* Finally, dispose our copy of the printer feedback and return status. */
  169.     DisposHandle(dataHandle);
  170.     return(status);
  171. }
  172.  
  173. /* ------------------------------------------------------------------------------------ */
  174. pascal Boolean NamerFilter(DialogPtr TheDialog, EventRecord *TheEvent, short *ItemHit)
  175. {
  176.     unsigned char    theKey;                    /* The ASCII code from the event record */
  177.     short            retVal = false;            /* The return value */
  178.     char            newName[kNameBufLen];    /* The copy of the new name */
  179.     LWFUParmBlk        *pb;                    /* Pointer to our parameter block */
  180.     
  181.     /* Retrieve a pointer to our parameter block */
  182.     pb = (LWFUParmBlk *)((WindowPeek)TheDialog)->refCon;
  183.     
  184.     /* Trap keyDown and autoKey events */
  185.     if (TheEvent->what == keyDown || TheEvent->what == autoKey) {
  186.     
  187.         /* Grab the ASCII character code from the event record */
  188.         theKey = TheEvent->message & charCodeMask;
  189.         
  190.         if (theKey == kReturnKey || theKey == kEnterKey) {        
  191.             /* Return or Enter?  Hit the default button */
  192.             retVal = true;
  193.             *ItemHit = kNDRename;
  194.         } else if (theKey == kAtChar || theKey == kColonChar || theKey > kLowASCII) {
  195.             /* "@", ":", or a high ASCII character?  Eat event and beep */
  196.             SysBeep(5);
  197.             retVal = true;
  198.             *ItemHit = kNDDummy;
  199.         } else if (theKey != kBackspaceKey) {
  200.             /* Key other than backspace?  Check length, decide whether to take the key */
  201.             pb->callBacks->GetPText(TheDialog, kNDNewName, newName);
  202.             if (*newName >= kMaxNameLength) {
  203.                 SysBeep(5);
  204.                 retVal = true;
  205.                 *ItemHit = kNDDummy;
  206.             } else retVal = false;
  207.         }
  208.     } else retVal = false;
  209.     return(retVal);
  210. }
  211.  
  212. /* ------------------------------------------------------------------------------------ */
  213. short RenamePrinter(LWFUParmBlk *pb)
  214. {
  215.     DialogPtr            nameDlg;                /* Pointer to the Rename dialog */
  216.     short                itemHit;                /* Item hit from ModalDialog */
  217.     char                psBuffer[150];            /* Buffer for out PostScript code */
  218.     char                newName[kNameBufLen];    /* New printer name from editText item */
  219.     char                blankStr[1];            /* Blank string used everywhere */
  220.     short                status;                    /* The status from ExitBufferRtn */
  221.     Point                where;                    /* Used for positioning the dialog */
  222.     LWFUCallBackInfo    *cb;                    /* Cached pointer to the callback array */
  223.     Boolean                doneFlag = false;        /* Flags to dismiss the dialog */
  224.     Boolean                renameFlag = false;        /* Flags whether to do rename operation */
  225.     Boolean                retVal = false;            /* TRUE or FALSE on success */
  226.  
  227.     /*
  228.         First, clear blankStr (used all over the place), and get the dialog from
  229.         the resource file.  Also, set up cb, a cached version of the callback structure
  230.         pointer, so can elminate half the pointer math for each callback.
  231.     */
  232.     *blankStr = 0;
  233.     nameDlg = GetNewDialog(pb->resSpace + kNamerDlg, nil, (WindowPtr)-1);
  234.     cb = pb->callBacks;
  235.     
  236.     /*
  237.         Now, using a handy callback, center our "Rename printer" dialog box on the
  238.         main screen.  CenterDialog sets a point which we should use for the top, left
  239.         of or dialog.  So, we MoveWindow the (still hidden) dialog to where.h, where.v.
  240.     */
  241.     cb->CenterDialog(nameDlg, &where);
  242.     MoveWindow(nameDlg, where.h, where.v, true);
  243.     
  244.     /*
  245.         To be friendly, we put the current printer name in the dialog so the user can
  246.         see it.  No need to send PostScript to determine the printer name -- it's
  247.         already in pb's printerInfo record.  So, we just ParamText it in there.
  248.     */
  249.     ParamText(pb->printerInfo->currentPrinterName, blankStr, blankStr, blankStr);
  250.     
  251.     /*
  252.         Why be fascist?  We set the initial text of the new printer name to be blank.
  253.         Also, we install a user item to do the "bold outline" around the default button.
  254.         Handily, there's a callback to install a userItem procedure, AND there's a
  255.         callback userItem that does the bold outline item!  Wow!  Cool!
  256.     */
  257.     cb->SetPText(nameDlg, kNDNewName, blankStr);
  258.     cb->UserItem(nameDlg, kNDBoldOutline, cb->BoldOutlineItem);
  259.     
  260.     /*
  261.         Now that everything's set up, let's put up the dialog.  In order to allow our
  262.         dialog filter (NamerFilter) to have access to our LWFUParmBlk, we install a
  263.         pointer to the block into the dialog window's refCon field, then ShowWindow the
  264.         dialog.
  265.     */
  266.     (LWFUParmBlk *)((DialogPeek)nameDlg)->window.refCon = pb;
  267.     ShowWindow((WindowPtr)nameDlg);
  268.     
  269.     /*
  270.         Now hit ModalDialog until the guy does something.  NamerFilter will ensure
  271.         the guy doesn't enter any illegal characters (like @ and :, which aren't
  272.         allowed in PostScript printer names) and will also make sure the length of
  273.         the name is okay.  If the guy dismisses the dialog with the kNDRename button,
  274.         then we set the renameFlag to TRUE, telling us we should rename the printer.
  275.     */
  276.     do {
  277.         ModalDialog(NamerFilter, &itemHit);
  278.         switch(itemHit) {
  279.             case kNDRename:        /* Rename */
  280.                 renameFlag = doneFlag = true;
  281.                 break;
  282.             case kNDCancel:        /* Cancel */
  283.                 doneFlag = true;
  284.                 break;
  285.         }
  286.     } while (!doneFlag);
  287.     
  288.     /*
  289.         First, hide the dialog window.  If the guy hit the "Rename" button, then
  290.         we need to retrieve the new name and send some PostScript code to rename
  291.         the printer.
  292.     */
  293.     HideWindow((WindowPtr)nameDlg);
  294.     if (renameFlag) {
  295.     
  296.         /*
  297.             The first part of renaming the printer is to construct a suitable
  298.             PostScript program.  The program in PostScript to rename the printer
  299.             is basically this:
  300.             
  301.             serverdict begin
  302.             0 exitserver
  303.             statusdict begin
  304.                 (NewPrinterName) setprintername
  305.             end
  306.             
  307.             where NewPrinterName is the actual text of the new printer name.  So
  308.             we've stored the first part (up thru the open parenthese) as one string
  309.             in our string list, and the last part (from the closed parenthese thru
  310.             the "end") in another string.  So to construct the program we just take
  311.             the string kRenameStartStr, append the name from the dialog, then append
  312.             kRenameEndStr.  Do we need to write code to concatenate Pascal strings?
  313.             No way, dude!  Callbacks!  (GetAndAppend is like GetIndString except that
  314.             it appends the string to the input instead of replacing the input).
  315.         */
  316.         GetIndString(psBuffer, pb->resSpace + kNamerStrs, kRenameStartStr);
  317.         cb->GetPText(nameDlg, kNDNewName, newName);
  318.         cb->Pstrcat(psBuffer, newName);
  319.         cb->GetAndAppend(psBuffer, pb->resSpace + kNamerStrs, kRenameEndStr);
  320.         
  321.         /*
  322.             Now we need to send our nifty little rename program to the printer.  The
  323.             first step is opening the printer with OpenPrinter().  If successful, we
  324.             send the program with DoWrite, also passing a pointer to our "feedback
  325.             analyzer," ExitBufferRtn.  It'll parse the output from the printer and
  326.             return a status code.  ExitBufferRtn's status code will in turn be returned
  327.             as the result of DoWrite, so we can see whether the rename operation was
  328.             successful.  Even if the DoWrite returned some ugly status, we still need
  329.             to close the printer with ClosePrinter.
  330.         */
  331.         if ((status = cb->OpenPrinter()) == noErr) {
  332.             status = cb->DoWrite(psBuffer + 1, (short)*psBuffer, sendEOF, pb, ExitBufferRtn);
  333.             cb->ClosePrinter();
  334.         }
  335.         
  336.         /*
  337.             If status was noErr (in other words, the rename operation was successful),
  338.             then we put up an alert telling the user he needs to choose the newly-
  339.             renamed printer in the Chooser.  The alert kindly reminds him what he
  340.             renamed the printer to.
  341.             
  342.             If status was some error, we put up an alert that says an error occured.
  343.         */
  344.         cb->UseCursor(0);
  345.         if (status == noErr) {
  346.             retVal = true;
  347.             ParamText(newName, blankStr, blankStr, blankStr);
  348.             cb->PositionAlert(pb->resSpace + kVerifyAlrt);
  349.             CautionAlert(pb->resSpace + kVerifyAlrt, nil);
  350.         } else {
  351.             retVal = false;
  352.             cb->PositionAlert(pb->resSpace + kFailAlrt);
  353.             StopAlert(pb->resSpace + kFailAlrt, nil);
  354.         }
  355.     }
  356.     
  357.     /*
  358.         Now we dispose or (hidden) dialog, and return TRUE/FALSE on the success of the
  359.         operation.
  360.     */
  361.     DisposDialog(nameDlg);
  362.     return(retVal);
  363. }
  364.